package n7.restaurant.java.Entity;

import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;

import n7.restaurant.java.Enum.Acces;
import n7.restaurant.java.Enum.Etat_Serveur;

public class Apprendi extends Agent {
	private Vector<String> taches = new Vector<String>();
	public static Vector<Apprendi> apprendis = new Vector<Apprendi>();
	private String toString;

	public String getToString() {
		return toString;
	}

	public void setToString(String toString) {
		this.toString = toString;
	}

	/**
	 * Block
	 * */
	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// il y a tache a faire?
			/* System.out.println(this.getId() + " " + this.getEtat()); */
			if (this.getEtat() == Etat_Serveur.waiting && hasNewTache()) {
				// obtenir tous les taches(nom d'ingredient)
				this.setTaches(getNomIngredients());
				this.setEtat(Etat_Serveur.doing);
			} else if (taches.size() != 0) {
				// if (this.getEtat_mentaux().size() != 0) {
				// System.out.println(this);
				// }
				Position returnPoint = new Position(60, 35, Acces.SALLE_CUISINE);
				// boucle
				// obtenir chaque ingredients -> si taches.size!=0
				// si connait son position -> move

				String tache = taches.firstElement();
				Acces lieu = hasKnownPosition(tache);
				// l'apprendi sait la position de l'ingredient.
				if (lieu != null) {
					// si l'apprendi est dans cet entrepot
					if (this.getPosition().getLieu() == lieu) {
						// supprimer la tache.
						foundIt(tache);
						deleteTache();
						taches.remove(0);
					} else if (this.getPosition().getLieu() != Acces.SALLE_CUISINE) {
						// l'apprendi est dans un entrepot
						// return to return point, apres aller au entrepot
						// correct
						Position portePosition = Porte.getAccesPosition(this
								.getPosition().getLieu(), Acces.SALLE_CUISINE);
						passerSalle(portePosition);
						moveToTask(returnPoint);
					} else {
						// l'apprendi est dans la salle de cuisine.
						Position portePosition = Porte.getAccesPosition(lieu,
								Acces.SALLE_CUISINE);
						// arrive a la porte
						passerSalle(portePosition);
						Vector<Ingredient> ingredients = new Vector<Ingredient>();
						// obtenir les ingredients dans cet entrepot.
						switch (lieu) {
						case ENTREPOT_A:
							ingredients = Entrepot.entrepots.get(0)
									.getIngredients();
							break;
						case ENTREPOT_B:
							ingredients = Entrepot.entrepots.get(1)
									.getIngredients();
							break;
						case ENTREPOT_C:
							ingredients = Entrepot.entrepots.get(2)
									.getIngredients();
							break;
						}

						Position tachePosition = null;
						for (Iterator<Ingredient> i = ingredients.iterator(); i
								.hasNext();) {
							Ingredient ig = i.next();
							if (ig.getNom().equalsIgnoreCase(tache)) {
								tachePosition = ig.getPosition();
								break;
							}
						}
						moveToTask(tachePosition);
						// supprimer la tache
						foundIt(tache);
						deleteTache();
						taches.remove(0);
					}
				} else {
					// si non, boucle
					// cherche depuis EntrepotA -> jusq'a trouve
					// informer a l'etat mental et aux autre apprendis son
					// position
					// -> ajoute know(AP0,lieu(oeuf)=EntrepotA)
					// supprime want(AP0,canFound(oeuf));
					// supprime dans taches
					/*
					 * System.out.println(this.getId() + " " +
					 * "sait pas la position");
					 */
					Acces init = this.getPosition().getLieu();
					// dans la position initial, l'apprendi est dans un entrepot
					if (init != Acces.SALLE_CUISINE) {
						Vector<Ingredient> ingredients = new Vector<Ingredient>();
						// obtenir les ingredients dans cet entrepot.
						switch (init) {
						case ENTREPOT_A:
							ingredients = Entrepot.entrepots.get(0)
									.getIngredients();
							break;
						case ENTREPOT_B:
							ingredients = Entrepot.entrepots.get(1)
									.getIngredients();
							break;
						case ENTREPOT_C:
							ingredients = Entrepot.entrepots.get(2)
									.getIngredients();
							break;
						}
						boolean isFound = false;
						for (Iterator<Ingredient> i = ingredients.iterator(); i
								.hasNext();) {
							Ingredient ig = i.next();
							/* System.out.println(ig.getNom()); */
							if (ig.getNom().equalsIgnoreCase(tache)) {
								// trouve accidentellement
								isFound = true;
								// supprimer la tache
								informerAutreApprendis(tache, init);
								foundIt(tache);
								deleteTache();
								taches.remove(0);
								break;
							}
						}
						if (isFound) {
							continue;
						} else {
							Position portePosition = Porte.getAccesPosition(
									init, Acces.SALLE_CUISINE);
							// arrive a la porte
							passerSalle(portePosition);
							moveToTask(returnPoint);
						}
					} else {
						Position tachePosition = null;
						for (int i = 0; i < 3; i++) {
							Entrepot e = Entrepot.entrepots.get(i);
							Acces entrepot = Acces.ENTREPOT_A;
							switch (i) {
							case 0:
								entrepot = Acces.ENTREPOT_A;
								break;
							case 1:
								entrepot = Acces.ENTREPOT_B;
								break;
							case 2:
								entrepot = Acces.ENTREPOT_C;
							}
							// obtenir destination
							// obtenir la position de porte de la destination
							Position portePosition = Porte.getAccesPosition(
									entrepot, Acces.SALLE_CUISINE);

							/*
							 * System.out.println(portePosition.getX() + " " +
							 * portePosition.getY() + " " +
							 * portePosition.getLieu());
							 */

							passerSalle(portePosition);
							// cherche ingredients dans la destination.
							Vector<Ingredient> ingredients = e.getIngredients();
							/* System.out.println("Tache" + ": " + tache); */
							for (Iterator<Ingredient> j = ingredients
									.iterator(); j.hasNext();) {
								Ingredient ig = j.next();
								/* System.out.println(ig.getNom()); */
								// il y a l'ingredient dans l'entrepot
								if (ig.getNom().equalsIgnoreCase(tache)) {
									tachePosition = ig.getPosition();
									/* System.out.println("Trouve"); */
								}
							}
							// found ingredient
							if (tachePosition != null) {
								// supprimer la tache et informer tous les
								// apprendis
								moveToTask(tachePosition);
								informerAutreApprendis(tache,
										tachePosition.getLieu());
								foundIt(tache);
								deleteTache();
								taches.remove(0);
								break;
							} else {
								// not found, quit entrepot
								// arrive a la return point
								moveToTask(returnPoint);
							}
						}
					}
				}
			} else if (this.getEtat() == Etat_Serveur.doing) {
				// System.out.println("Fini");
				// if (this.getEtat_mentaux().size() != 0) {
				// System.out.println(this);
				// }
				// l'apprendi fini tous les taches et il donne tous ingredients
				// au specialiste.
				getNumeroSpecialiste();
			}
			// fini ses taches.
			// quand fini la boucle, aller a la specialiste,
			// donner les ingredients
			// supprime
			// knowref(AP0,donneTache(SP0));

			// rentree au position initial
			// etat ->free
			if (this.getEtat() != Etat_Serveur.free && taches.isEmpty()) {
				/* System.out.println(this); */
				int numeroSpecialiste = getNumeroSpecialiste();
				/* System.out.println(numeroSpecialiste); */
				Specialiste sp = Specialiste.specialistes
						.get(numeroSpecialiste);
				if (this.getPosition().getLieu() != Acces.SALLE_CUISINE) {
					Position tachePosition = Porte.getAccesPosition(this
							.getPosition().getLieu(), Acces.SALLE_CUISINE);
					// aller a la porte
					passerSalle(tachePosition);
					// aller au specialiste
					moveToTask(sp.getPosition());
				} else {
					// aller au specialiste
					moveToTask(sp.getPosition());
				}

				// System.out.println(this);
				informerAuSpecialisteFiniTache(sp);
				int numeroAP = Integer.parseInt(this.getId().substring(2));
				Position p = new Position(
						(Salle_Principale.LONGUEUR_SALLE_PRINCIPALE
								+ Salle_Cuisine.LONGUEUR_SALLE_CUISINE - 10),
						10 + numeroAP * 10, Acces.SALLE_CUISINE);
				moveToTask(p);
				this.setEtat(Etat_Serveur.free);
			}
		}
	}

	/**
	 * informer au specialiste que la tache est fini
	 * */
	private void informerAuSpecialisteFiniTache(Specialiste sp) {
		// TODO Auto-generated method stub
		// knowif(SP0,tache(AP0)=fini)
		synchronized (Apprendi.class) {
			Etat_Mental em = new Etat_Mental();
			em.setAgent_X(sp);
			em.setDescription("knowref");
			em.setFormule("tache(" + this.getId() + ")=fini");
			sp.addEtatMental(em);
		}
		// supprimer
		// know(AP0,wasfound(oeuf));
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			if (em.getDescription().equalsIgnoreCase("know")
					&& em.getFormule().contains("wasFound")) {
				this.getEtat_mentaux().remove(i);
				i--;
			}
		}
		// suppprimer
		// knowref(AP0,donneTache(SP0));
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			if (em.getDescription().equalsIgnoreCase("knowref")
					&& em.getFormule().contains("donneTache(SP")) {
				this.getEtat_mentaux().remove(i);
				break;
			}
		}
	}

	/**
	 * obtenir le numero de specialiste qui me donne la tache
	 * */
	private int getNumeroSpecialiste() {
		// TODO Auto-generated method stub
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			// cherche
			// knowref(AP0,donneTache(SP0));
			if (em.getFormule().contains("donneTache(SP")) {
				/* System.out.println(em.getFormule()); */
				return Integer.parseInt(em.getFormule().substring(13, 14));
			}
		}
		return -1;
	}

	/**
	 * Informer autre apprendis que l'ingredient est ou.
	 * */
	private void informerAutreApprendis(String tache, Acces init) {
		// TODO Auto-generated method stub
		synchronized (Apprendi.class) {
			for (int i = 0; i < Apprendi.apprendis.size(); i++) {
				Apprendi ap = Apprendi.apprendis.get(i);
				Etat_Mental em = new Etat_Mental();
				em.setAgent_X(ap);
				em.setDescription("know");
				em.setFormule("lieu(" + tache + ")" + "=" + init.toString());
				ap.addEtatMental(em);
			}
		}
	}

	private void foundIt(String tache) {
		// TODO Auto-generated method stub
		Etat_Mental em = new Etat_Mental();
		em.setDescription("know");
		em.setFormule("wasFound(" + tache + ")");
		em.setAgent_X(this);
		this.addEtatMental(em);
	}

	/**
	 * supprimer la tache qui a deja fini
	 * */
	private boolean deleteTache() {
		// TODO Auto-generated method stub
		String firstTache = taches.firstElement();
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			if (em.getFormule().contains("canFound(" + firstTache)) {
				this.getEtat_mentaux().remove(i);
				return true;
			}
		}
		return false;
	}

	private Acces hasKnownPosition(String tache) {
		// TODO Auto-generated method stub
		// cherche
		// know(AP0,lieu(oeuf)=EntrepotA);
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			String formule = em.getFormule();
			if (formule.equalsIgnoreCase("lieu(" + tache + ")")) {
				StringTokenizer st = new StringTokenizer(formule, "=", true);
				st.nextToken();
				String lieu = st.nextToken();
				return Acces.valueOf(lieu);
			}
		}
		return null;
	}

	/**
	 * obtenir tous les ingredients dans la tache.
	 * */
	private Vector<String> getNomIngredients() {
		// TODO Auto-generated method stub
		Vector<String> nomsIngredient = new Vector<String>();
		// cherche
		// want(AP0,canFound(oeuf))
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			String formule = em.getFormule();
			if (formule.contains("canFound")
					&& em.getDescription().equalsIgnoreCase("want")) {
				int length = formule.length();
				String nomIngredient = formule.substring(9, length - 1);
				nomsIngredient.add(nomIngredient);
			}
		}
		return nomsIngredient;
	}

	// Est-ce qu'il y a un nouvel tache?
	private boolean hasNewTache() {
		// TODO Auto-generated method stub
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			if (em.getFormule().contains("donneTache(SP")) {
				return true;
			}
		}
		return false;
	}

	@Override
	public String toString() {
		String returnString = this.getId() + ": \n";
		for (int i = 0; i < this.getEtat_mentaux().size(); i++) {
			Etat_Mental em = this.getEtat_mentaux().get(i);
			returnString += em.toString() + "\n";
		}
		returnString += "knowref(" + this.getId() + ",etat(" + this.getId()
				+ ")=" + this.getEtat().toString() + ")";
		return returnString+"\n";
	}

	public Vector<String> getTaches() {
		return taches;
	}

	public void setTaches(Vector<String> taches) {
		this.taches = taches;
	}

	public void passerSalle(Position p) {
		int id = Integer.parseInt(this.getId().substring(2, 3));

		int this_x = this.getPosition().getX();
		int this_y = this.getPosition().getY();
		Apprendi ap = Apprendi.apprendis.get(id);
		if (this_y >= p.getY()) {
			while (Math.abs(this_y - p.getY()) >= 3) {
				this_y -= 3;
				ap.setPosition_Y(this_y);
				delay(400);
			}
			ap.setPosition_Y(p.getY());
		} else {
			while (Math.abs(p.getY() - this_y) >= 3) {
				this_y += 3;
				ap.setPosition_Y(this_y);
				delay(400);
			}
			ap.setPosition_Y(p.getY());
		}
		if (this_x >= p.getX()) {
			while (Math.abs(this_x - p.getX()) >= 3) {
				this_x -= 3;
				ap.setPosition_X(this_x);
				delay(400);
			}
			ap.setPosition_X(p.getX());
		} else {
			while (Math.abs(p.getX() - this_x) >= 3) {
				this_x += 3;
				ap.setPosition_X(this_x);
				delay(400);
			}
			ap.setPosition_X(p.getX());
		}
		ap.getPosition().setLieu(p.getLieu());
	}

	public void delay(int time) {
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * deplacer au position du task
	 * */
	public void moveToTask(Position p) {
		int id = Integer.parseInt(this.getId().substring(2, 3));

		int this_x = this.getPosition().getX();
		int this_y = this.getPosition().getY();
		Apprendi ap = Apprendi.apprendis.get(id);
		if (this_y >= p.getY()) {
			while (Math.abs(this_y - p.getY()) >= 3) {
				this_y -= 3;
				ap.setPosition_Y(this_y);
				delay(400);
			}
		} else {
			while (Math.abs(p.getY() - this_y) >= 3) {
				this_y += 3;
				ap.setPosition_Y(this_y);
				delay(400);
			}
		}
		if (this_x >= p.getX()) {
			while (Math.abs(this_x - p.getX()) >= 3) {
				this_x -= 3;
				ap.setPosition_X(this_x);
				delay(400);
			}
		} else {
			while (Math.abs(p.getX() - this_x) >= 3) {
				this_x += 3;
				ap.setPosition_X(this_x);
				delay(400);
			}
		}
		// this.setEtat(Etat_Serveur.waiting);
	}

	public void setPosition_X(int x) {
		this.getPosition().setX(x);
	}

	public void setPosition_Y(int y) {
		this.getPosition().setY(y);
	}
}
